昨天我們快速地看過作業系統需要達成的主要目標,包含抽象,多工等等。而在這一篇章,我們將了解作業系統的主要服務以及 xv6 作業系統的相關背景,以及 xv6 作業系統所提供的功能,以及支援的 System call,了解如何啟動 xv6 作業系統與使用 debug mode 來啟動 xv6。
xv6 為 MIT 用於教學用的簡單作業系統 (6.828, 6S081 作業系統課程),xv6 為 UNIXv6 以及 x86 組合語言這兩個詞所結合而成,UNIXv6 為第一個對外公開的 UNIX 版本,由 Ken Thompson 和 Dennis Ritchie 所開發。在 2019 年後,6.828, 6S081 課程改成使用 RISC-V 版本的 xv6 進行教學。xv6 使用 ANSI C 以及組合語言進行開發。xv6 為 UNIX Like 的多核心 RISC-V 作業系統
xv6 的 kernel 部分有兩種實做,一種是為了 x86 架構而設計的,平台為多核心 x86,另外一種為使用 RISC-V 設計的,在 RISC-V 中,使用的是64位元的處理器。
在本文,將使用 RISC-V 實作 kernel 的 xv6,也就是讓 xv6 在RISC-V 架構的 CPU 上執行,理論上可以讓 xv6 在一台 RISC-V 的機器上執行,但是在本文,為了避免硬體架構帶來的不方便以及影響,將使用模擬器 QEMU 來模擬 RISC-V 架構並且執行 xv6。
xv6 為共享記憶體多核心作業系統 (shared-memory multiprocessor),128 MB 的主記憶體是共享的。而 xv6 主要實作出了作業系統以下功能
多核心系統,平行系統 (parallel),這種系統擁有多個處理器,並且共用匯流排以及時脈,記憶體,周圍 I/O 裝置等等,這種系統主要有以下優點
現代的電腦架構系統大致上可以使用下圖進行表示 :
<from Operating System Concept (9 th Edition)>
在後面介紹 kernel virtual address space 時,我們可以看到 xv6 所使用的 I/O 裝置 (也就是上圖中,device 的部分),這邊先大致上提及 :
記憶體管理需要完成紀錄目前記憶體資源是由誰正在使用,以及決定哪一些 process 的資料需要移入或移出記憶體空間,和決定 process 配置以及回收記憶體空間,用於管理記憶體的單位稱為一個分頁 (page)。
kalloc.c
中。sleep()
, wakup()
。環境: Ubuntu 20.04 LTS
安裝工具 : QEMU 5.1+, GDB 8.3+, GCC, and Binutils.
sudo apt-get install git build-essential gdb-multiarch qemu-system-misc gcc-riscv64-linux-gnu binutils-riscv64-linux-gnu
git clone實驗環境 xv6-2021
git clone git://g.csail.mit.edu/xv6-labs-2021
cd xv6-labs-2021
git checkout util
啟動xv6
make qemu
使用Ctrl-A X
即可退出。
可以看到我們的 xv6 是跑在一個稱為 QEMU 的模擬器上,而 QEMU 這個模擬器,我們可以將其簡單的看做下面裝置
< The HiFive Unleashed board >
我們應該想像成 xv6 跑在上面這一塊板子上。
QEMU 內部有一個 gdb server,我們可以通過 gdb 連線到該 server 去對 xv6 進行 debug,操作為在一個視窗使用 debug mode 啟動 xv6,接著會等待連線
make qemu-gdb
接著我們可以在另外一個視窗,啟動交互式 gdb (另一個視窗需要在 xv6 目錄底下)
gdb-multiarch
我們就能夠在左方的 gdb 視窗進行除錯,可以通過kernel.asm
得知函式所在的記憶體地址,使用 gdb 對該地址下斷點進行除錯。
Makefile 會去讀取 C 原始碼,接著通過編譯器,產生出 A.S
,這是 RISC-V 格式的組合語言檔案,接著再通過組譯器,產生出A.O
,目的檔為二進位格式的組合語言,而 Makefile 會對所有 C 原始碼進行這一些操作,接下來 Loader 會將這一些目的檔通過鏈結器產生出 kernel file,QEMU 會執行他,在課程中為了方便除錯,還會產生出kernel.asm
,可以方便讓我們得知每一條指令的記憶體地址,通過 gdb 下斷點進行除錯。
如果要自行擴充 user program,需要將原始碼 .c 放置於 user 資料夾中,接著需要修改 Makefile 檔案,在UPROGS
底下加入原始碼名稱,格式為U/_name\
。
/kernel/syscall.h
// System call numbers
#define SYS_fork 1
#define SYS_exit 2
#define SYS_wait 3
#define SYS_pipe 4
#define SYS_read 5
#define SYS_kill 6
#define SYS_exec 7
#define SYS_fstat 8
#define SYS_chdir 9
#define SYS_dup 10
#define SYS_getpid 11
#define SYS_sbrk 12
#define SYS_sleep 13
#define SYS_uptime 14
#define SYS_open 15
#define SYS_write 16
#define SYS_mknod 17
#define SYS_unlink 18
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
System call 可以大概分成六大類型
fork()
exit()
wait()
open()
read()
write()
close()
ioctl()
read()
write()
getpid()
alarm()
sleep()
pip()
chmod()
xv6-riscv
Operating System Concepts, 9/e